#include "stdTcpServer.h"
/* 构造函数 */
StdTcpSocket::StdTcpSocket() : m_sockAttr(std::make_unique<stdTcpSocketPrivate>())
{
    m_sockAttr->m_connfd = -1;
    m_sockAttr->m_connected = false;
}
/* 析构函数 */
StdTcpSocket::~StdTcpSocket()
{
    if (m_sockAttr->m_connfd > 0)
    {
        close(m_sockAttr->m_connfd);
    }
}
/* 连接服务器 */
int StdTcpSocket::connectToServer(const char *ip, int port)
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1)
    {
        perror("socket error: ");
        return -1;
    }

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);
    const char *serverIp = ip;
    inet_pton(AF_INET, serverIp, &(serverAddr.sin_addr.s_addr));

    int ret = connect(sockfd, reinterpret_cast<struct sockaddr *>(&serverAddr), sizeof(serverAddr));
    if (ret != 0)
    {
        perror("connect error: ");
        return -1;
    }

    m_sockAttr->m_connfd = sockfd;
    m_sockAttr->m_connected = true;

    return ret;
}
/* 是否连接成功 */
bool StdTcpSocket::isConnected() const
{
    return m_sockAttr->m_connected;
}
/*发送数据*/
int StdTcpSocket::sendMessage(const std::string &sendMsg)
{
    return sendMessage((const void *)sendMsg.c_str(), sendMsg.size());
}
/* 发送数据 */
int StdTcpSocket::sendMessage(const void *sendMsg, size_t n)
{
    /* 1.先发数据包的大小 */
    int writeBytes = write(m_sockAttr->m_connfd, (const void *)&n, sizeof(n));
    if (writeBytes < 0)
    {
        perror("write error:");
        return -1;
    }

    /* 2.再写数据本身 */
    writeBytes = write(m_sockAttr->m_connfd, sendMsg, n);
    if (writeBytes < 0)
    {
        perror("write error:");
        return -1;
    }
    return writeBytes;
}
/* 接收数据 */
int StdTcpSocket::recvMessage(std::string &recvMsg)
{
    /* 1.先读数据包的大小 */
    size_t size = 0;
    int readBytes = read(m_sockAttr->m_connfd, (void *)&size, sizeof(size_t));
    if (readBytes < 0)
    {
        perror("read error:");
        return -1;
    }

    /* 程序到这个地方:就可以知道后面的数据有多长 */
    char *msg = new char[size + 1];
    
    /* 清除脏数据 */
    memset(msg, 0, sizeof(char) * (size + 1));

    int totalReceived = 0;
    while (totalReceived < size)
    {
        size_t received = read(m_sockAttr->m_connfd, msg + totalReceived, size - totalReceived);
        if (received <= 0)
        {
            perror("read error:");
            delete[] msg;
            return -1;
        }
        totalReceived += received;
    }
    /* 接收到的数据 */
    recvMsg = msg;
    delete[] msg;

    return totalReceived;
}
/* 接收数据 */
int StdTcpSocket::recvMessage(void *buf, size_t n)
{
    int readBytes = read(m_sockAttr->m_connfd, buf, n);

    return readBytes;
}
/* 设置属性 */
stdTcpSocketPrivate *StdTcpSocket::getSockAttr() const
{
    return m_sockAttr.get();
}

StdTcpServer::StdTcpServer() : m_port(8080), m_tcpAttr(std::make_unique<stdTcpServerPrivate>())
{
    m_tcpAttr->m_sockfd = -1;
    m_tcpAttr->m_isRunning = false;
}

StdTcpServer::~StdTcpServer()
{
    if (m_tcpAttr->m_sockfd > 0)
    {
        close(m_tcpAttr->m_sockfd);
    }
}
/*设置监听*/
bool StdTcpServer::setListen(int port)
{
    this->m_port = port;
    m_tcpAttr->m_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_tcpAttr->m_sockfd == -1)
    {
        perror("socket error: ");
        throw std::runtime_error("socket create failed");
    }

    /*设置端口复用*/
    int optVal = 1;
    int ret = setsockopt(m_tcpAttr->m_sockfd, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal));
    if (ret != 0)
    {
        perror("bind error: ");
        return false;
    }

    /*绑定IP和端口信息*/
    struct sockaddr_in localAddress;
    /*清空结构体的脏数据*/
    memset(&localAddress, 0, sizeof(localAddress));
    /*地址族是IPV4*/
    localAddress.sin_family = AF_INET;
    localAddress.sin_port = htons(m_port);
    /*设置全通规则*/
    localAddress.sin_addr.s_addr = htonl(INADDR_ANY);

    bind(m_tcpAttr->m_sockfd, reinterpret_cast<struct sockaddr *>(&localAddress), sizeof(localAddress));

    /*设置监听*/
    ret = listen(m_tcpAttr->m_sockfd, 10);
    if (ret != 0)
    {
        perror("listen error: ");
        throw std::runtime_error("listen failed");
    }

    m_tcpAttr->m_isRunning = true;

    return true;
}
/*接受客户端的连接*/
std::shared_ptr<StdTcpSocket> StdTcpServer::getClientSock()
{
    int clientConnfd = accept(m_tcpAttr->m_sockfd, NULL, NULL);
    if (clientConnfd == -1)
    {
        perror("accept error: ");
        throw std::runtime_error("accept failed");
    }

    std::cout << "clientConnfd: " << clientConnfd << std::endl;

    /*通讯类*/
    auto client = std::make_shared<StdTcpSocket>();

    /*套接字*/
    client->getSockAttr()->m_connfd = clientConnfd;
    client->getSockAttr()->m_connected = true;

    return client;
}
